/* **********************************************************************
版本: 2022.3.62f1
作者: wzz
日期: 2025-8-1
描述: 作用 TouchSocket， 官网：https://touchsocket.net/
***********************************************************************/

using LogPro;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Sockets;
using TcpClient = TouchSocket.Sockets.TcpClient;

#pragma warning disable 4014

namespace Framework
{
    public class NetTcp : IBaseNet
    {
        private TcpClient mTcpClient;
        private NetMgr mNetMgr;

        /// <summary>
        /// 正在连接的Ip, 空为没有连接
        /// </summary>
        public string Ip
        {
            get
            {
                if (mTcpClient == null)
                    return string.Empty;

                return mTcpClient.RemoteIPHost.EndPoint.GetIP();
            }
        }

        /// <summary>
        /// 正在连接的Port, 空为没有连接
        /// </summary>
        public int Port
        {
            get
            {
                if (mTcpClient == null)
                    return 0;
                return mTcpClient.RemoteIPHost.Port;
            }
        }


        public NetTcp(NetMgr netMgr)
        {
            mNetMgr = netMgr;
        }

        /// <summary>
        /// 请求连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void ConnectAsync(string ip, int port)
        {
            TcpConnectAsync(ip, port);
        }

        private async Task TcpConnectAsync(string ip, int port)
        {
            try
            {
                if (mTcpClient != null)
                {
                    var remoteIp = mTcpClient.RemoteIPHost.EndPoint.GetIP();
                    var remotePort = mTcpClient.RemoteIPHost.Port;
                    if (mTcpClient.Online)
                    {
                        Log($"已连接：{remoteIp}:{remotePort}");
                        return;
                    }

                    Log($"正在连接中：{remoteIp}:{remotePort}");
                    return;
                }

                IPAddress ipAddress;
                if (!IPAddress.TryParse(ip, out ipAddress))
                {
                    LogWarning("请输入正确的ip地址");
                    return;
                }
                IPHost iPHost = new IPHost(ipAddress, port);

                mTcpClient = new TcpClient();
                mTcpClient.Connected += OnConnected;
                mTcpClient.Closed += OnClosed;
                mTcpClient.Received += OnReceived;

                await mTcpClient.SetupAsync(new TouchSocketConfig()
                .SetRemoteIPHost(iPHost)
                .ConfigureContainer(a =>
                {
                })
                .SetMaxBufferSize(10240)
                .SetNoDelay(true)
                .SetTcpDataHandlingAdapter(() =>

                new FixedHeaderPackageAdapter() // 固定包头
                {
                    FixedHeaderType = FixedHeaderType.Int // 注意前后端必须一致，否则发送接收，收不到任何回调
                })
                );

                await mTcpClient.ConnectAsync();

                // 至此 mTcpClient.Online 才为 true
            }
            catch (Exception e)
            {
                var msg = e.Message.Replace("\0", "").Replace("\r\n", "");
                LogWarning(msg);
                mNetMgr.Destroy();
                mNetMgr.PupNetEvent(NetMgr.ENetCode.ConnectError, msg);
            }
        }

        /// <summary>
        /// 成功连接
        /// </summary>
        /// <param name="tcpClient"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public Task OnConnected(ITcpClient tcpClient, ConnectedEventArgs e)
        {
            Log($"连接成功：{Ip}:{Port}");
            mNetMgr.PupNetEvent(NetMgr.ENetCode.Connected, string.Empty);
            return EasyTask.CompletedTask;
        }

        /// <summary>
        /// 收到信息,需要将数据压入消息队列
        /// </summary>
        /// <param name="tcpClient"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public Task OnReceived(ITcpClient tcpClient, ReceivedDataEventArgs e)
        {
            //通常protobuff,处理需要传byte[], 不管是lua还是c#最终都是要传byte[]
            mNetMgr.PupReceiveMsgBytes(e.ByteBlock.Span.ToArray());

            return EasyTask.CompletedTask;
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="tcpClient"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public Task OnClosed(ITcpClient tcpClient, ClosedEventArgs e)
        {
            // 根据实际使用情况调用：
            // 1.断线时，重连不会下发最新消息
            // 2.断线时，重连请求重连服务会下发最新消息
            // 目前大部分游戏，重连都会推最新消息过来，所以需在清理
            mNetMgr.ClearReceiveMsgBytes();

            if (e.Manual)
            {
                // 主动断开
                Log($"主动断开连接：{Ip}:{Port}");
            }
            else
            {
                var msg = $"异常断开连接：{Ip}:{Port} Error:{e.Message}";
                LogWarning(msg);
                mNetMgr.Destroy();
                mNetMgr.PupNetEvent(NetMgr.ENetCode.Disconnect, msg);
            }

            return EasyTask.CompletedTask;
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="msg"></param>
        public async void SendMsg(byte[] msg)
        {
            if (mTcpClient == null)
            {
                LogWarning("客户端未启动！");
                return;
            }
            if (!mTcpClient.Online)
            {
                LogWarning("客户端未连线");
                return;
            }
            try
            {
                // 注意，发送空字符，会抛出失败：
                await mTcpClient.SendAsync(msg);
            }
            catch (Exception e)
            {
                LogWarning($"发送失败：{e.Message}");
            }
        }

        /// <summary>
        /// 普通信息
        /// </summary>
        public void Log(string log)
        {
            LogPro.DebugPro.Log(log, LogPro.LogColor.Green);
        }

        /// <summary>
        /// 警告信息
        /// </summary>
        public void LogWarning(string log)
        {
            LogPro.DebugPro.LogWarning(log);
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public void Destroy()
        {
            if (mTcpClient == null)
            {
                return;
            }
            mTcpClient.Dispose();
            mTcpClient = null;
        }
    }
}